package my.netty.concurrent;

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

public abstract class MultiThreadEventExecutorGroup implements EventExecutorGroup {

    protected final EventExecutor[] children;

    private final EventExecutorChooser chooser;

    public MultiThreadEventExecutorGroup(int threads) {
        this(threads, null);
    }

    public MultiThreadEventExecutorGroup(int threads, ThreadFactory threadFactory) {
        if (threads <= 0) {
            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", threads));
        }
        children = new EventExecutor[threads];

        if (threadFactory == null) {
            threadFactory = newDefaultThreadFactory();
        }

        for (int i = 0; i < threads; i ++) {
            boolean success = false;
            try {
                // 直接传ThreadFactory不太合适，可以学源码里面再包装一层
                children[i] = newChild(threadFactory);
                success = true;
            } catch (Exception e) {
                throw new IllegalStateException("failed to create a child event loop", e);
            } finally {
                if (!success) {
                    // 如果第一个线程执行器就没创建成功，剩下的方法都不会执行
                    // 如果从第二个线程执行器开始，执行器没有创建成功，那么就会关闭之前创建好的线程执行器。
                    for (int j = 0; j < i; j ++) {
                        children[j].shutdownGracefully();
                    }
                    for (int j = 0; j < i; j ++) {
                        EventExecutor e = children[j];
                        try {
                            // 判断正在关闭的执行器的状态，如果还没终止，就等待一些时间再终止
                            while (!e.isTerminated()) {
                                e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                            }
                        } catch (InterruptedException interrupted) {
                            // 给当前线程设置一个中断标志
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
            }
        }
        chooser = new PowerOfTwoEventExecutorChooser(children);
    }

    private ThreadFactory newDefaultThreadFactory() {
        return new DefaultThreadFactory(getClass());
    }

    @Override
    public void shutdownGracefully() {

    }

    @Override
    public boolean isTerminated() {
        return false;
    }

    @Override
    public void awaitTermination(Integer integer, TimeUnit timeUnit) throws InterruptedException {

    }

    protected abstract EventExecutor newChild(ThreadFactory threadFactory) throws Exception;

    @Override
    public EventExecutor next() {
        return chooser.next();
    }
}
